<template>
  <view class="tui-charts__line-wrap" :style="{ width: width + 'rpx' }">
    <view class="tui-line__legend" v-if="legend.show">
      <view
        class="tui-line__legend-item"
        v-for="(item, index) in dataset"
        :key="index"
      >
        <view
          class="tui-line__legend-circle"
          :style="{ backgroundColor: item.color }"
        ></view>
        <text
          :style="{
            fontSize: (legend.size || 24) + 'rpx',
            lineHeight: (legend.size || 24) + 'rpx',
            color: legend.color || '#333'
          }"
          >{{ item.name }}</text
        >
      </view>
    </view>
    <view
      class="tui-charts__line-box"
      v-if="xAxis.length > 0 && dataset.length > 0"
      :style="{ width: width + 'rpx' }"
    >
      <scroll-view
        :scroll-x="scrollable"
        class="tui-line__scroll-view"
        :style="{ height: scrollViewH + 'rpx' }"
      >
        <view :style="{ height: (xAxisVal.height || 48) + 'rpx' }"></view>
        <view class="tui-charts__line" :style="{ height: height + 'rpx' }">
          <view
            class="tui-line__item"
            :class="{ 'tui-line__flex-1': !scrollable }"
            :style="{ width: (xAxisLine.itemGap || 120) + 'rpx' }"
            v-for="(item, index) in xAxis"
            :key="index"
          >
            <view
              class="tui-line__xAxis-text"
              :style="{
                color: xAxisLabel.color || '#333',
                fontSize: (xAxisLabel.size || 24) + 'rpx'
              }"
            >
              {{ item }}
            </view>
            <view
              class="tui-yAxis__split-line"
              :style="{
                borderRightStyle: yAxisSplitLine.type || 'dashed',
                borderRightColor: yAxisSplitLine.color || '#e3e3e3'
              }"
              v-if="tooltipShow && index == activeIdx"
            >
            </view>
            <view
              class="tui-xAxis__tickmarks"
              :style="{
                height: xAxisTick.height || '12rpx',
                backgroundColor: xAxisTick.color || '#e3e3e3'
              }"
            >
            </view>
          </view>
          <view v-for="(dot, i) in dots" :key="dot.id">
            <view
              class="tui-charts__line-dot"
              :class="{
                'tui-charts__dot-enlarge': tooltipShow && j == activeIdx
              }"
              @tap.stop="dotClick(i, j)"
              v-for="(d, j) in dot.source"
              :key="d.id"
              :style="{
                bottom: d.y + 'rpx',
                left: d.x + 'rpx',
                width: (brokenDot.width || 12) + 'rpx',
                height: (brokenDot.width || 12) + 'rpx',
                borderColor: dot.color || brokenDot.color,
                background: brokenDot.color || dot.color
              }"
            >
              <text
                class="tui-line__val"
                :style="{
                  fontSize: (xAxisVal.size || 24) + 'rpx',
                  color: xAxisVal.color
                }"
                v-if="xAxisVal.show"
              >
                {{ getYAxisVal(i, j) }}
              </text>
            </view>
          </view>

          <view v-for="(line, idx) in lines" :key="line.id">
            <view
              class="tui-charts__broken-line"
              v-for="(l, k) in line.source"
              :key="l.id"
              :style="{
                height: brokenLineHeight + 'px',
                background: line.color,
                bottom: l.y + 'rpx',
                left: l.x + 'rpx',
                width: l.width + 'rpx',
                '-webkit-transform': `rotate(${l.angle}deg)`,
                transform: `rotate(${l.angle}deg)`
              }"
            >
            </view>
          </view>
          <view
            class="tui-area__chart-box"
            v-for="(area, i) in dots"
            :key="area.key"
            :style="{
              left: xGap / 2 + 'rpx',
              right: xGap / 2 + 'rpx',
              minWidth: xWidth + 'rpx'
            }"
          >
            <view
              class="tui-area__item"
              :style="{
                '--tui-area-start': model.start,
                '--tui-area-end': model.end,
                background: model.background
              }"
              v-for="(model, j) in area.area"
              :key="j"
            ></view>
          </view>
        </view>
      </scroll-view>
      <view
        class="tui-line__border-left"
        :style="{
          height: height + (xAxisVal.height || 48) + 'rpx',
          backgroundColor: yAxisLine.color || '#e3e3e3'
        }"
      >
      </view>
      <view
        class="tui-xAxis__line"
        :class="{ 'tui-line__first': index === 0 }"
        :style="{
          bottom:
            index * (yAxisLine.itemGap || 60) +
            (xAxisLabel.height || 60) +
            'rpx',
          borderTopStyle: index === 0 ? 'solid' : splitLine.type,
          borderTopColor: index === 0 ? xAxisLine.color : splitLine.color
        }"
        v-for="(item, index) in yAxisData"
        :key="index"
      >
        <text
          class="tui-yAxis__val"
          :style="{
            color: item.color || yAxisLabel.color,
            fontSize: (yAxisLabel.size || 24) + 'rpx'
          }"
          v-if="yAxisLabel.show"
          >{{ item.value }}</text
        >
      </view>
    </view>

    <view
      class="tui-line__tooltip"
      v-if="tooltip"
      :class="{ 'tui-line__tooltip-show': tooltipShow }"
    >
      <view class="tui-tooltip__title">{{ xAxis[activeIdx] || '' }}</view>
      <view
        class="tui-line__tooltip-item"
        v-for="(item, index) in tooltips"
        :key="index"
      >
        <view
          class="tui-line__legend-circle"
          :style="{ backgroundColor: item.color }"
        ></view>
        <text class="tui-tooltip__val">{{ item.name }}</text>
        <text class="tui-tooltip__val tui-tooltip__val-ml">{{ item.val }}</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  name: 'tui-charts-area',
  emits: ['click'],
  props: {
    //图表宽度
    width: {
      type: [Number, String],
      default: 620
    },
    //图例，说明
    legend: {
      type: Object,
      default() {
        return {
          show: false,
          size: 24,
          color: '#333'
        }
      }
    },
    tooltip: {
      type: Boolean,
      default: false
    },
    xAxis: {
      type: Array,
      default() {
        return []
      }
    },
    //默认选中x轴索引
    currentIndex: {
      type: Number,
      default: -1
    },
    //分割线
    splitLine: {
      type: Object,
      default() {
        return {
          //分割线颜色,不显示则将颜色设置为transparent
          color: '#e3e3e3',
          type: 'dashed'
        }
      }
    },
    //x轴刻度线
    xAxisTick: {
      type: Object,
      default() {
        return {
          height: '12rpx',
          //不显示则将颜色设置为transparent
          color: '#e3e3e3'
        }
      }
    },
    //x轴线条
    xAxisLine: {
      type: Object,
      default() {
        return {
          color: '#e3e3e3',
          //x轴item间距 rpx
          itemGap: 120
        }
      }
    },
    xAxisLabel: {
      type: Object,
      default() {
        return {
          color: '#333',
          size: 24,
          height: 60
        }
      }
    },
    xAxisVal: {
      type: Object,
      default() {
        return {
          show: true,
          color: '#333',
          size: 24,
          //如果show为true且val显示的时候，height需要设置一定的值保证val能显示完整 rpx
          height: 48
        }
      }
    },
    //点击坐标点所显示的分割线
    yAxisSplitLine: {
      type: Object,
      default() {
        return {
          //分割线颜色,不显示则将颜色设置为transparent
          color: 'transparent',
          type: 'dashed'
        }
      }
    },
    //折线坐标点宽度 rpx
    brokenDot: {
      type: Object,
      default() {
        return {
          width: 12,
          //点的背景色
          color: '#F8F8F8'
        }
      }
    },
    //折线高度/粗细 px
    brokenLineHeight: {
      type: [Number, String],
      default: 1
    },
    //y轴数据，如果不传则默认使用min,max值计算
    // {
    // 	value: 0,
    // 	color: "#333"
    // }
    yAxis: {
      type: Array,
      default() {
        return []
      }
    },
    //y轴最小值
    min: {
      type: Number,
      default: 0
    },
    //y轴最大值
    max: {
      type: Number,
      default: 100
    },
    //y轴分段递增数值
    splitNumber: {
      type: Number,
      default: 20
    },
    yAxisLine: {
      type: Object,
      default() {
        return {
          //不显示则将颜色设置为transparent
          color: '#e3e3e3',
          //y轴item间距 rpx
          itemGap: 60
        }
      }
    },
    yAxisLabel: {
      type: Object,
      default() {
        return {
          show: true,
          color: '#333',
          size: 24
        }
      }
    },
    //是否可滚动
    scrollable: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      height: 0,
      scrollViewH: 0,
      sections: 0,
      yAxisData: [],
      activeIndex: -1,
      activeIdx: -1,
      tooltips: [],
      tooltipShow: false,
      timer: null,
      dots: [],
      lines: [],
      /*========options============*/
      /*
					name: '', 
					color: '',
					source: []
					colorFormatter:Function
				*/
      dataset: [],
      xAxisValFormatter: null,
      maxValue: 1,
      xGap: 120,
      xWidth: 600
    }
  },
  created() {
    this.init()
    this.activeIdx = this.currentIndex
  },
  // #ifndef VUE3
  beforeDestroy() {
    this.clearTimer()
  },
  // #endif
  // #ifdef VUE3
  beforeUnmount() {
    this.clearTimer()
  },
  // #endif
  methods: {
    getPx(rpx) {
      let px = parseInt(uni.upx2px(Number(rpx)))
      return px % 2 === 0 ? px : px + 1
    },
    getYAxisVal(idx, index) {
      let showVal = this.dataset[idx].source[index]
      if (
        this.xAxisVal.formatter &&
        typeof this.xAxisVal.formatter === 'function'
      ) {
        showVal = this.xAxisVal.formatter(showVal)
      } else if (
        this.xAxisValFormatter &&
        typeof this.xAxisValFormatter === 'function'
      ) {
        showVal = this.xAxisValFormatter(showVal)
      }
      return showVal
    },
    generateArray(start, end) {
      return Array.from(new Array(end + 1).keys()).slice(start)
    },
    getValue(val) {
      return val < 0 ? 0 : val
    },
    getCoordinatePoint() {
      const xAxis = [...this.xAxis]
      const xSections = xAxis.length
      const ySections = this.yAxisData.length - 1
      const itemGap = this.scrollable
        ? this.xAxisLine.itemGap || 120
        : this.width / xSections
      let dots = []
      let radius = (this.brokenDot.width || 12) / 2
      this.xWidth = itemGap * (xSections - 1)
      this.xGap = itemGap
      let yHeight = (this.yAxisLine.itemGap || 60) * ySections
      this.dataset.map((item, index) => {
        let source = item.source || []
        let dotArr = []
        let areaArr = []
        source.map((val, idx) => {
          let y = this.getValue(
            ((val - this.min) / (this.maxValue - this.min)) * yHeight - radius
          )
          dotArr.push({
            id: 'd' + idx,
            x: this.getValue((0.5 + idx) * itemGap - radius),
            y: y
          })
          if (idx !== xSections - 1) {
            let y1 = this.getValue(
              ((source[idx + 1] - this.min) / (this.maxValue - this.min)) *
                yHeight -
                radius
            )
            areaArr.push({
              start: (y + 6) / yHeight,
              end: (y1 + 6) / yHeight,
              background: item.color
            })
          }
        })

        dots.push({
          id: 'dd' + index,
          color: item.color,
          source: dotArr,
          key: 'ar' + index,
          area: areaArr
        })
      })
      this.dots = dots
      this.drawLines(dots)
    },
    drawLines(dots) {
      let lines = []
      // dots是点的集合 : Array<{ x: number; y: number; }>
      let radius = (this.brokenDot.width || 12) / 2
      dots.map((item, idx) => {
        let dotArr = item.source
        let lineArr = []
        dotArr.map((dot, index) => {
          if (!dotArr[index + 1]) return
          const AB = {
            x: dotArr[index + 1].x - dot.x,
            y: dotArr[index + 1].y - dot.y,
            y1: dot.y - dotArr[index + 1].y
          }
          const v = Math.sqrt(Math.pow(AB.x, 2) + Math.pow(AB.y, 2))
          const angle = Math.atan2(AB.y1, AB.x) * (180 / Math.PI)
          lineArr.push({
            id: 'l' + index,
            x: dot.x + radius,
            y: dot.y + radius - 1,
            width: v,
            angle:
              AB.y1 > 0
                ? Math.sqrt(Math.pow(angle, 2))
                : -Math.sqrt(Math.pow(angle, 2))
          })
        })
        lines.push({
          id: 'll' + idx,
          color: item.color,
          source: lineArr
        })
      })
      this.lines = lines
    },
    init() {
      this.maxValue = this.max
      let itemGap = this.yAxisLine.itemGap || 60
      let sections = this.yAxis.length - 1
      let yAxis = this.yAxis
      if (sections <= 0) {
        sections = Math.ceil((this.max - this.min) / this.splitNumber)
        let sectionsArr = this.generateArray(0, sections)
        yAxis = sectionsArr.map((item) => {
          return {
            value: item * this.splitNumber + this.min
          }
        })
        this.maxValue = yAxis[yAxis.length - 1].value
      }
      this.yAxisData = yAxis
      this.sections = sections + 1
      this.height = itemGap * sections
      const valH = this.xAxisVal.height || 48
      this.scrollViewH = this.height + (this.xAxisLabel.height || 60) + valH
      this.getCoordinatePoint()
    },
    /*
			dataset：面积图表数据
			xAxisValFormatter :格式化面积拐点value值
			*/
    draw(dataset, xAxisValFormatter) {
      this.xAxisValFormatter = xAxisValFormatter || null
      this.dataset = dataset || []
      this.init()
    },
    clearTimer() {
      clearTimeout(this.timer)
      this.timer = null
    },
    tooltipHandle(index) {
      let data = [...this.dataset]
      let tooltips = []
      data.forEach((item) => {
        let color = item.color
        if (item.colorFormatter && typeof item.colorFormatter === 'function') {
          color = item.colorFormatter(item.source[index])
        }
        tooltips.push({
          color: color,
          name: item.name,
          val: item.source[index]
        })
      })
      this.tooltips = tooltips
      this.clearTimer()
      this.tooltipShow = true
      this.timer = setTimeout(() => {
        this.tooltipShow = false
      }, 5000)
    },
    dotClick(index, idx) {
      this.activeIndex = index
      this.activeIdx = idx
      this.tooltipHandle(idx)
      this.$emit('click', {
        datasetIndex: index,
        sourceIndex: idx,
        ...this.dataset[index]
      })
    }
  }
}
</script>

<style scoped>
.tui-charts__line-wrap {
  position: relative;
  transform: rotate(0deg) scale(1);
  /* margin: 0 auto; */
}

.tui-line__legend {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}

.tui-line__legend-item {
  display: flex;
  align-items: center;
  margin-left: 24rpx;
  margin-bottom: 30rpx;
}

.tui-line__legend-circle {
  height: 20rpx;
  width: 20rpx;
  border-radius: 50%;
  margin-right: 8rpx;
  flex-shrink: 0;
}

.tui-charts__line-box {
  position: relative;
  padding-left: 1px;
  box-sizing: border-box;
  transform-origin: 0 0;
  overflow: visible;
  transform: scale(1);
}

.tui-line__scroll-view {
  position: relative;
  z-index: 10;
  box-sizing: border-box;
}

.tui-charts__line {
  min-width: 100%;
  position: relative;
  display: flex;
  align-items: flex-end;
  /* overflow: hidden; */
  transform: rotate(0deg) scale(1);
}

.tui-line__between {
  justify-content: space-between;
}

.tui-line__item {
  height: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  position: relative;
  text-align: center;
  box-sizing: border-box;
  z-index: 10;
  transition: all 0.3s;
  flex-shrink: 0;
}

.tui-line__flex-1 {
  flex: 1;
}

.tui-xAxis__tickmarks {
  position: absolute;
  right: 0;
  width: 1px;
  transform: translateY(100%);
  bottom: 0;
}

.tui-yAxis__split-line {
  position: absolute;
  height: 100%;
  width: 0;
  border-right-width: 1px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
}

.tui-yAxis__area-line {
  position: absolute;
  height: 100%;
  width: 1px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
}

.tui-line__xAxis-text {
  width: 100%;
  position: absolute;
  left: 50%;
  bottom: 0;
  flex: 1;
  transform: translate(-50%, 100%);
  padding-top: 8rpx;
  word-break: break-all;
}

.tui-line__border-left {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  z-index: 11;
}

.tui-xAxis__line {
  width: 100%;
  height: 0;
  border-top-width: 1px;
  position: absolute;
  left: 0;
  display: flex;
  align-items: center;
}

.tui-line__first {
  z-index: 12;
}

.tui-yAxis__val {
  transform: translateX(-100%);
  padding-right: 12rpx;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  -webkit-font-smoothing: antialiased;
}

.tui-charts__line-dot {
  position: absolute;
  border-radius: 50%;
  transition: all 0.3s;
  z-index: 12;
  border-width: 1px;
  border-style: solid;
  box-sizing: border-box;
  /* #ifdef H5 */
  cursor: pointer;
  /* #endif */
}

.tui-line__val {
  width: 100%;
  position: absolute;
  top: 0;
  left: 50%;
  padding-bottom: 12rpx;
  transform: translate(-50%, -100%);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  -webkit-font-smoothing: antialiased;
  white-space: nowrap;
  z-index: 20;
}

.tui-charts__dot-enlarge {
  transform: scale(1.4);
}

.tui-charts__broken-line {
  position: absolute;
  transform-origin: 0 0;
  transition: all 0.3s;
  z-index: 10;
  border-color: transparent;
  box-sizing: border-box;
  /* transform: translateZ(0); */
  /* -webkit-backface-visibility:hidden; */
}

.tui-line__tooltip {
  padding: 30rpx;
  border-radius: 12rpx;
  background-color: rgba(0, 0, 0, 0.6);
  display: inline-block;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 20;
  visibility: hidden;
  opacity: 0;
  transition: all 0.3s;
}

.tui-line__tooltip-show {
  visibility: visible;
  opacity: 1;
}

.tui-tooltip__title {
  font-size: 30rpx;
  color: #fff;
  line-height: 30rpx;
}

.tui-line__tooltip-item {
  display: flex;
  align-items: center;
  padding-top: 24rpx;
  white-space: nowrap;
}

.tui-tooltip__val {
  font-size: 24rpx;
  line-height: 24rpx;
  color: #fff;
  margin-left: 6rpx;
}

.tui-tooltip__val-ml {
  margin-left: 20rpx;
}

.tui-area__chart-box {
  display: flex;
  position: absolute;
  top: 0;
  bottom: 0;
  transform: rotate(0deg) scale(1);
}

.tui-area__item {
  flex: 1;
  flex-shrink: 0;
  /* 120%:100%，-20%:0% ，改为px时恢复*/
  clip-path: polygon(
    0% calc(100% * (1 - var(--tui-area-start))),
    100% calc(100% * (1 - var(--tui-area-end))),
    120% 100%,
    -20% 100%
  );
}
</style>
